#ifndef AVALON_SERVICEPROTOCOLSERVLETCONTAINER_HPP
#define AVALON_SERVICEPROTOCOLSERVLETCONTAINER_HPP
#include <boost/functional/factory.hpp>
#include "Avalon/IO/ChannelAdapterServerConnection.hpp"
#include "Avalon/Services/ServiceProtocolServer.hpp"

namespace Avalon {
namespace Services {

  /*! \class ServiceProtocolServletContainer
      \brief Executes and manages a ServiceProtocolServlet.
      \tparam ServletType The type of servlet to manage.
   */
  template<typename ServletType, typename ChannelType>
  class ServiceProtocolServletContainer {
    public:

      //! Constructs the ServiceProtocolServletContainer.
      /*!
        \param serverConnection Accepts connections to the servlet.
        \param dataShuttleFactory The type of Message Serialization to use.
        \param servlet The Initializer for the servlet.
        \param threadPool Handles all asynchronous operations.
      */
      ServiceProtocolServletContainer(IO::ServerConnection* serverConnection,
        Serialization::DataShuttleFactory* dataShuttleFactory,
        const Initializer<ServletType>& servlet,
        Threading::ThreadPool& threadPool);

      ~ServiceProtocolServletContainer();

      //! Returns <code>true</code> iff the servlet is operational.
      bool IsOpen() const;

      //! Opens the servlet, serving its requests/responses.
      void Open();

      //! Closes the servlet, disconnecting all clients.
      void Close();

    private:
      friend class ServiceProtocolServlet<ServletType, ChannelType>;
      boost::mutex m_mutex;
      ServletType m_servlet;
      ServiceProtocolServer<ChannelType> m_protocolServer;
      bool m_isOpen;
      bool m_isClosing;

      template<typename Service>
      void SetHandler(const typename Service::Request::Slot& slot);
      void SendMessage(ChannelType* channel, const Message& message);
      void SendMessage(const std::vector<ChannelType*>& channels,
        const Message& message);
      void OnAccept(ChannelType* channel);
      void OnChannelClosed(ChannelType* channel);
      void OnServerConnectionClosed();
  };

  template<typename ServletType, typename ChannelType>
  ServiceProtocolServletContainer<ServletType, ChannelType>::
      ServiceProtocolServletContainer(IO::ServerConnection* serverConnection,
      Serialization::DataShuttleFactory* dataShuttleFactory,
      const Initializer<ServletType>& servlet,
      Threading::ThreadPool& threadPool)
      : m_servlet(servlet),
        m_isOpen(false),
        m_isClosing(false) {
    IO::ServerConnection* wrapperServerConnection =
      new IO::ChannelAdapterServerConnection(serverConnection,
      new IO::WrapperChannelFactory(IO::WrapperChannelFactory::ChannelCreator(
      &WrapperChannelFactory::WrapChannel<ChannelType>)));
    m_protocolServer.Initialize(wrapperServerConnection, dataShuttleFactory,
      boost::bind(&ServiceProtocolServletContainer::OnAccept, this,
      boost::arg<1>()), boost::bind(
      &ServiceProtocolServletContainer::OnChannelClosed, this, boost::arg<1>()),
      boost::bind(&ServiceProtocolServletContainer::OnServerConnectionClosed,
      this), threadPool);
  }

  template<typename ServletType, typename ChannelType>
  ServiceProtocolServletContainer<ServletType, ChannelType>::
      ~ServiceProtocolServletContainer() {
    Close();
  }

  template<typename ServletType, typename ChannelType>
  bool ServiceProtocolServletContainer<ServletType, ChannelType>::IsOpen()
      const {
    boost::lock_guard<boost::mutex> lock(m_mutex);
    return m_isOpen;
  }

  template<typename ServletType, typename ChannelType>
  void ServiceProtocolServletContainer<ServletType, ChannelType>::Open() {}

  template<typename ServletType, typename ChannelType>
  void ServiceProtocolServletContainer<ServletType, ChannelType>::Close() {}
}
}

#endif // AVALON_SERVICEPROTOCOLSERVLETCONTAINER_HPP
